﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Xml.Linq;
using devtm.Configuration;
using devtm.Configuration.Models;
using devtm.Editor.Configuration.ConfigurationProperties;
using devtm.Editor.Configuration.Data;
using devtm.Editor.Configuration.formWpf;
using devtm.Editor.Configuration.Messages;
using devtm.Helpers;
using devtm.Types.LazyLoading;
using devtm.Helpers.Factories;
using System.Collections.ObjectModel;
using System.Threading;
using devtm.Collections;
using System.Runtime.InteropServices;
using devtm.CommonInteractive;
using devtm.CommonInteractive.Types;



namespace devtm.Editor.Configuration
{
    
    /// <summary>
    /// Interaction logic for UserControl1.xaml
    /// </summary>
    public partial class UCConfigEdit : UserControl, INotifyPropertyChanged
    {


        public UCConfigEdit()
        {

            InitializeComponent();
            InitializeCommandBindings();

            this.Writer = new devtm.CommonInteractive.Output();
            this.Writer.TextInStream += Writer_TextInStream;

            _myproperties = this.myproperties;
            _dispatcher = this.Dispatcher;
            _configEdit = this;

            //if (Datas.Messages != null)
                //StatutList.ItemsSource = 
            Datas.Messages.CollectionChanged += Messages_CollectionChanged;
         
            Datas.ListeChange = new Command.CommandManager();

            Datas.ListeChange.PropertyChanged += ListeChange_PropertyChanged;

            Datas.LoadOptions();




            CanUndo = false;
            CanRedo = false;

            SaveParameter = new UCConfigEdit.SaveParameters();

        }

        void Messages_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {

            if (TextInStream == null)
                return;

            switch (e.Action )
            {

                case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                    foreach (object item in e.NewItems)
                        TextInStream(this, new OutputBaseEventHandlerEventArgs() { Action = System.Collections.Specialized.NotifyCollectionChangedAction.Add, Message = item });
                    break;
            
                case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                    foreach (object item in e.OldItems)
                        TextInStream(this, new OutputBaseEventHandlerEventArgs() { Action = System.Collections.Specialized.NotifyCollectionChangedAction.Remove, Message = item });
                    break;

                case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                    TextInStream(this, new OutputBaseEventHandlerEventArgs() { Action = System.Collections.Specialized.NotifyCollectionChangedAction.Reset });
                    break;

                case System.Collections.Specialized.NotifyCollectionChangedAction.Move:
                case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                default:
                    break;

            }

        }

        void Writer_TextInStream(object sender, EventHandlerEventArgs e)
        {
            if (TextInStream != null)
                TextInStream(this, new OutputBaseEventHandlerEventArgs() { Action = System.Collections.Specialized.NotifyCollectionChangedAction.Add, Message = e.text.Replace(@"\n", "") });
        }

        static System.Windows.Threading.Dispatcher _dispatcher;
        public static System.Windows.Threading.Dispatcher UniqueDispatcher
        {
            get
            {
                return _dispatcher;
            }
        }


        /// <summary>
        /// Inits the specified environment.
        /// </summary>
        /// <param name="environment">The environment.</param>
        /// <returns></returns>
        [STAThread]
        public bool Init(string[] environment)
        {

            devtm.Configuration.Parameters.ModeEdit = true;

            Datas.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(Datas_PropertyChanged);

            if (environment.Count() < 2)
                return false;

            String filename = environment[1];

            return Load(filename);

        }

        void Datas_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {



            if (e.PropertyName == "File")
            {

                MessageText msg1 = new MessageText(
                        Datas.Messages,
                        "Loaded configuration file " + Datas.FileConfiguration.FullName,
                        TypeMessage.Information)
                        {
                            Label = Properties.Resources.Close
                        };


                //msg1.Action =
                //    () => msg1.List.Remove(msg1);


                Datas.Messages.Add(msg1);

            }

            PropertyChange(e.PropertyName);
            PropertyChange("ItemCanMerge");

        }

        #region Load

        public bool Load(String filename)
        {

            TreeRoot.Items.Clear();

            Datas.ClearDirectoriesLibrairies();

            Datas.jobs.Add(() => LoadConfig());

            try
            {
                if (!Datas.OpenConfiguration(filename))
                {
                    MessageBox.Show(Datas.LastError.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    return false;
                }


            }
            catch (Exception)
            {
                
                throw;
            }

         

            Datas.jobs.Start(this.Dispatcher, true);

            PropertyChange("ListeProperties");
            PropertyChange("ItemCanMerge");

            return true;
        }

        private void LoadConfig()
        {

            ConfigurationSectionCollection sections = Datas.Configuration.Sections;

            TestConfigByXml(Datas.FileConfiguration);

            ElementSection item = new ElementSection(null, sections, Datas.FileConfiguration.Name, 20);
            TreeRoot.Items.Add(item);

            Items = item;

            foreach (String key in Datas.Configuration.SectionGroups.Keys)
            {

                var group = Datas.Configuration.SectionGroups[key];

                if (!Datas.ShowNode(group))
                    continue;

                Debug.Print(key);

                if (ElementSection.ExcludeType.Contains("|" + key + "|"))
                    continue;

                ElementSection s = new ElementSection(null, group, key, 20);
                if (s.Ignore)
                    break;
                item.Items.Add(s);
            }

            if (TreeRoot.Items.Count >= 1)
            {
                var n = TreeRoot.Items[0] as TreeViewItem;
                n.IsExpanded = true;
            }

            Datas.SaveOptions();
        }


        private void TestConfigByXml(FileInfo filename)
        {

            XDocument _mydoc = XDocument.Load(filename.FullName);
            Datas.Xml = _mydoc.Element("configuration");
            if (Datas.Xml != null)
            {

                List<FileInfo> Liste = filename.Directory.GetFiles("*.dll", SearchOption.AllDirectories).ToList();

                var elsect = Datas.Xml.Element("configSections");
                if (elsect != null)
                {
                    // recherche toutes les sections en recursif.
                    foreach (XElement node in elsect.Descendants("section"))
                    {
                        String a = (string)node.Attribute("type");
                        if (!String.IsNullOrEmpty(a))
                        {

                            String[] tb = a.Split(',');

                            if (tb.Length < 2)
                            {
                                string message = string.Format("Mismatch string type definition at {0}.\nThe format type must be (Type fullname, Assembly file name without extension)\n\n{1}", node.GetPath(), node.ToString());
                                MessageBox.Show(message, "Mismatch format", MessageBoxButton.OK, MessageBoxImage.Error);
                                continue;
                            }

                            FileInfo test = null;
                            string namefile = tb[1] + ".dll";
                            foreach (FileInfo item in Liste)
                                if (item.Name == namefile.Trim())
                                    test = item;


                            if (test == null)
                            {
                                // message pour dll manquante.
                                continue;
                            }

                            string version2;
                            Assembly ass;
                            try
                            {
                                ass = System.Reflection.Assembly.LoadFile(test.FullName);
                                Match match2 = Regex.Match(a, @"Version=\d+\.\d+\.\d+\.\d+");
                                version2 = match2.Value;
                                if (!String.IsNullOrEmpty(version2))
                                {
                                    version2 = version2.Substring(8);
                                }
                                else
                                    continue;

                            }
                            catch (Exception)
                            {
                                // message chargement de la librairie
                                continue;
                            }




                            Match match = Regex.Match(a, @"Version=\d+\.\d+\.\d+\.\d+");
                            String version = match.Value;
                            if (!String.IsNullOrEmpty(version))
                            {
                                version = version.Substring(8);
                            }


                            if (version2 != version)
                            {

                            }

                        }


                    }
                }
            }
        }

        #region Comments

        //private static String FindType(DirectoryInfo dir, String assemblyName, String typeName, String version)
        //{
        //    Debug.Print(typeName);
        //    //String retour = String.Empty;
        //    foreach (FileInfo file in dir.GetFiles(assemblyName.Trim() + ".dll", SearchOption.AllDirectories))
        //    {

        //        // on le charge
        //        Assembly ass = Assembly.LoadFile(file.FullName);

        //        String AssVersion = String.Empty;
        //        if (!String.IsNullOrEmpty(version))
        //        {
        //            Match match = Regex.Match(ass.FullName, @"Version=\d+\.\d+\.\d+\.\d+");
        //            AssVersion = match.Value.Substring(8);
        //        }

        //        var ret = CheckAssemblies(dir, ass);
        //        if (ret == null)
        //            continue;

        //        List<String> MissingAssemblies = ret;

        //        try
        //        {
        //            // on tourne dans les types
        //            foreach (Type type in ass.GetTypes())
        //            {
        //                if (type.FullName == typeName)
        //                {
        //                    if (String.IsNullOrEmpty(version))
        //                        return String.Empty;
        //                    else
        //                    {
        //                        if (version == AssVersion)
        //                            return String.Empty;
        //                        else
        //                        {
        //                            return "Wrong version from " + file.FullName;
        //                        }
        //                    }
        //                }
        //            }
        //        }
        //        catch (System.Reflection.ReflectionTypeLoadException e)
        //        {
        //            String Msg = @"Erreur : \n";
        //            foreach (var item in e.LoaderExceptions)
        //            {
        //                Msg = item.Message;
        //                break;
        //            }

        //            // on a planté
        //            foreach (String miss in MissingAssemblies)
        //                Msg += miss + @"\n";

        //            return Msg;
        //        }

        //    }

        //    return String.Empty;
        //}

        //private static List<String> CheckAssemblies(DirectoryInfo dir, Assembly ass)
        //{
        //    // On verifie que les assemblies nécéssaires sont présents.
        //    List<String> MissingAssemblies = new List<String>();
        //    foreach (var Ass1 in ass.GetReferencedAssemblies())
        //    {
        //        if (Ass1.Name == "mscorlib" || Ass1.Name.StartsWith("System"))
        //            continue;
        //        var lst = (dir.GetFiles(Ass1.Name + ".dll", SearchOption.AllDirectories));
        //        if (lst.Count() == 0)
        //            MissingAssemblies.Add(Ass1.FullName);
        //        else
        //        {
        //            try
        //            {
        //                Assembly ass2 = Assembly.LoadFile(lst.FirstOrDefault().FullName);
        //                var ret = CheckAssemblies(dir, ass2);
        //                if (ret == null)
        //                    return ret;

        //                MissingAssemblies.AddRange(ret);
        //            }
        //            catch (Exception e)
        //            {

        //                String Msg = String.Format("Error on assembly {0}. \n {1}", Ass1.FullName, e.Message);
        //                MessageBox.Show(Msg);
        //                return null;
        //            }


        //        }

        //    }
        //    return MissingAssemblies;
        //}

        #endregion

        #endregion

        #region Actions

        /// <summary>
        /// Sauve
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Save()
        {
            Datas.SaveConfiguration(SaveParameter.Fusion, SaveParameter.ConfigurationMode, SaveParameter.ForceSave);
        }

        public bool IsModified
        {
            get { return Datas.IsModified; }

        }

        /// <summary>
        /// Sauve
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Open()
        {

            using (System.Windows.Forms.OpenFileDialog file = new System.Windows.Forms.OpenFileDialog()
            {

                Filter = "File Config|*.config",
                Multiselect = false,
                CheckFileExists = true

            })


                if (file.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    Load(file.FileName);



        }

        /// <summary>
        /// Add brique
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void AddSection()
        {
            AddSection(String.Empty);
        }

        private void AddSection(string filename)
        {

            if (Datas.FileConfiguration == null)
                return;

            SelectAssembly frm = new SelectAssembly(
                Datas.DirectoriesSearch,
                new TypeContraint(typeof(ConfigurationSection)),
                filename
                );

            Datas.LoadTypes(Datas.DirectoriesSearch);

            frm.ShowDialog();

            if (String.IsNullOrEmpty(frm.Retour))
                return;

            DefaultSectionNameAttribute attr =
                (DefaultSectionNameAttribute)Attribute.GetCustomAttribute(frm.TypeRetour, typeof(DefaultSectionNameAttribute));

            var toto = (ConfigurationSection)Activator.CreateInstance(frm.TypeRetour, null);


            String DefaultName = toto.GetType().FullName.ToLower(CultureInfo.CurrentCulture);
            if (attr != null)
                DefaultName = attr.Name;


            FieldInfo f1 = frm.TypeRetour.GetField("DefaultName");
            if (f1 != null)
                DefaultName = (string)f1.GetValue(toto);


            CreateSection(toto, DefaultName);


        }

        private void CreateSection(ConfigurationSection section, String name)
        {

            String makey = String.Empty;

            makey = InputBox.ShowDialog(Properties.Resources.WriteTheNameOfTheSection, Properties.Resources.NewSection, name
                , new InputBoxValidator((c1) => VerifieNode(c1), Properties.Resources.ThisKeyIsAllreadyUsed)
                , new InputBoxValidator((c1) => Regex.IsMatch(c1, @"\w+"), Properties.Resources.WrongFormat)
            );

            if (String.IsNullOrEmpty(makey))
                return;

            Datas.Configuration.Sections.Add(makey, section);

            ElementSection items = (this.TreeRoot.Items[0] as ElementSection);
            IElementSection sectionE = items.AddConfigurationElement(section, makey);
            sectionE.ContextTitle.Inherited = System.Windows.Visibility.Hidden;
            sectionE.CanDel = true;

            int index = (sectionE.ParentItem as ElementSection).Items.IndexOf(section);
            //var configSection = Da =tas.Configuration.GetSection(makey);
            Command.CommandHelpers.HasAddedSection(index, sectionE);
        }

        private bool VerifieNode(string c1)
        {

            foreach (var item in Datas.Configuration.Sections.Keys)
                if (item.ToString() == c1)
                    return false;

            foreach (var item in Datas.Configuration.SectionGroups.Keys)
                if (Equals(item, c1))
                    return false;

            return true;
        }

        public void AddItem()
        {

            ElementSection item = TreeRoot.SelectedItem as ElementSection;

            foreach (IElementAction act in item.ButtonActions)
            {
                if (act.IsForChildren)
                    continue;

                if (act.TypeAction == EnumAction.Add)
                    act.Action();

            }

            //Datas.IsModified = true;
            item.ExpandSubtree();

        }

        public void EditItem()
        {

            ElementSection item = TreeRoot.SelectedItem as ElementSection;

            foreach (IElementAction act in item.ButtonActions)
            {

                if (act.IsForChildren)
                    continue;

                if (act.TypeAction == EnumAction.Edit)
                    act.Action();

            }

            //Datas.HasUpdated(item.Section, item.ConfigurationElement, TypeChange.Change, null, null);

            item.ExpandSubtree();

        }


        #region Del

        /// <summary>
        /// Del brique
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>        
        public void RemoveSection()
        {

            ElementSection item = TreeRoot.SelectedItem as ElementSection;
            if (!item.CanDel)
                return;

            if (item.ConfigurationElement != null)
            {

                if (item.ConfigurationElement is ConfigurationSection)
                {

                    if (MessageBox.Show(
                        Properties.Resources.AreYouSureYouWantRemoveThisSection,
                        Properties.Resources.RemoveSection,
                        MessageBoxButton.YesNo,
                        MessageBoxImage.Warning,
                        MessageBoxResult.Yes) == MessageBoxResult.Yes)
                        DelSection(item);

                }
                else if (item.ConfigurationElement is ConfigurationElement)
                {

                    if (MessageBox.Show(
                        Properties.Resources.AreYouSureYouWantRemoveThisItem,
                        Properties.Resources.RemoveSection,
                        MessageBoxButton.YesNo,
                        MessageBoxImage.Warning,
                        MessageBoxResult.Yes) == MessageBoxResult.Yes)
                        DelItem(item);

                }

            }
        }

        public void DelSection(IElementSection i)
        {

            if (i == null)
                return;

            try
            {

                int index = (i.ParentItem as ElementSection).Items.IndexOf(i);
                Datas.Configuration.Sections.Remove((i.ConfigurationElement as ConfigurationSection).SectionInformation.Name);

                Command.CommandHelpers.HasRemovedSection(index, i);

                (i.ParentItem as TreeViewItem).Items.Remove(i);


            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message + e.ToString());
            }
        }

        internal void ReplaceSection(ElementSection elementSection, string configurationSection, bool withUndo)
        {

            string old = elementSection.RawXml.ToString();

            ConfigurationSection c = elementSection.ConfigurationElement as ConfigurationSection;

            // on recreer           
            elementSection.SetRawXml(configurationSection);

            if (withUndo)
            {

                Action methodUndo = () => ReplaceSection(elementSection, old, false);
                Action methodRedo = () => ReplaceSection(elementSection, configurationSection, withUndo);

                Command.CommandHelpers.HasUpdated(
                    elementSection,
                    elementSection.ConfigurationElement, methodRedo, methodUndo);

            }

        }

        private void DelItem(IElementSection i)
        {

            if (i == null)
                return;

            try
            {
                IElementSection parent = i.ParentItem;
                if (parent.HasCollectionType.ToString().EndsWith("Collection"))
                {

                    switch (parent.HasCollectionType)
                    {
                        case EnumTypeConfiguration.Default:
                            break;

                        case EnumTypeConfiguration.ConnectionStringCollection:
                            ActionsHelper.RemoveConnectionString(i, parent);
                            break;

                        case EnumTypeConfiguration.KeyValueCollection:
                            ActionsHelper.RemoveKeyValueCollection(i, parent);
                            break;

                        default:

                            IElementAction j = parent.ButtonActions.Where(c => c.TypeAction == EnumAction.Remove).FirstOrDefault();

                            if (j.Method != null)
                            {

                                switch (j.Parameter)
                                {
                                    case TypeParametre.None:
                                    case TypeParametre.MethodParameter:
                                        ExecuteRemove(j, i);
                                        break;
                                    case TypeParametre.Section:
                                        ExecuteRemoveWithConfigurationElement(j, i);

                                        break;
                                    case TypeParametre.StringName:
                                        ExecuteRemoveWithStringName(j, i);
                                        break;
                                    default:
                                        break;
                                }

                            }
                            else
                                j.Action();

                            break;
                    }

                }
                else
                {

                }

            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message + e.ToString());
            }
        }






        private void ExecuteRemove(IElementAction j, IElementSection i)
        {

            var k = j.Method.GetParameters();
            if (k.Length > 0)
            {
                Type t = k.First().ParameterType;
                if (t == typeof(string))
                    ExecuteRemoveWithStringName(j, i);

                else if (t.IsOfType(typeof(ConfigurationElement)))
                    ExecuteRemoveWithConfigurationElement(j, i);

                else
                    throw new Exception("The type " + t.FullName + " is not supported by UCConfigEdit.ExecuteRemove.");
            }

        }


        private void ExecuteRemoveWithStringName(IElementAction j, IElementSection i)
        {

            MethodInfo m = j.Method;

            IElementSection parent = i.ParentItem;

            string name = (string)i.GetElementName;

            var o = j.IsForChildren ? parent.ConfigurationElement : i.ConfigurationElement;

            m.Invoke(o, new object[] { name });

            // trouver le Add
            MethodInfo MethodUndo = AccessPrivatePropertyHelper.GetMethod(o, "BaseAdd").Where(new { element = typeof(ConfigurationElement) }).First();

            Command.CommandHelpers.HasAddedItemToList(i, o, m, name, MethodUndo, i.ConfigurationElement, Command.TypeChange.Remove);
            (parent as ElementSection).Items.Remove(i);

        }


        private void ExecuteRemoveWithConfigurationElement(IElementAction j, IElementSection i)
        {
            MethodInfo m = j.Method;

            IElementSection parent = i.ParentItem;
            (parent as ElementSection).Items.Remove(i);

            MethodInfo k = null;
            foreach (IElementAction item in i.ButtonActions)
            {
                if (item.TypeAction == EnumAction.Remove)
                {
                    k = item.Method;
                    break;
                }
            }

            Command.CommandHelpers.HasAddedItemToList(i, i.ParentItem.ConfigurationElement, m, k, i.ConfigurationElement, Command.TypeChange.Remove);
            m.Invoke(i.ParentItem.ConfigurationElement, new object[] { i.ConfigurationElement });

        }

        #endregion

        public void Close()
        {

            Datas.Watcher.quit = true;

            Datas.CloseConfiguration();

            Datas.ListeChange.PropertyChanged -= ListeChange_PropertyChanged;

            if (Jober._Jobs != null)
            {
                Jober._Jobs.Clear();
                Datas.jobs.Close = true;
            }

            
        }

        #region Drag and drop

        private void TreeRoot_DragEnter(object sender, DragEventArgs e)
        {

            if (e.Data.GetDataPresent("FileDrop", true))
            {
                String[] items = (String[])e.Data.GetData("FileDrop");
                foreach (String item in items)
                    // is fichier config
                    if (
                        item.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) ||
                        (item.EndsWith(".Config", StringComparison.OrdinalIgnoreCase) && !item.EndsWith(".Config.Config", StringComparison.OrdinalIgnoreCase))
                        )
                        if (File.Exists(item))
                        {
                            e.Effects = DragDropEffects.Copy;
                            return;
                        }
            }

            e.Effects = DragDropEffects.None;

        }

        private void TreeRoot_Drop(object sender, DragEventArgs e)
        {

            String[] j = e.Data.GetFormats();

            if (e.Data.GetDataPresent("FileDrop", true))
            {
                String[] items = (String[])e.Data.GetData("FileDrop");
                foreach (String item in items)
                {
                    // is fichier config
                    if (item.EndsWith(".Config", StringComparison.OrdinalIgnoreCase) && !item.EndsWith(".Config.Config", StringComparison.OrdinalIgnoreCase))
                    {
                        if (File.Exists(item))
                        {
                            PolicyDrop(item);
                            return;
                        }
                    }
                    else if (item.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
                    {
                        if (File.Exists(item))
                        {

                            AddSection(item);
                            return;
                        }
                    }
                }

            }

            if (e.Data.GetDataPresent("Text", true))
            {
                try
                {
                    String Item = (String)e.Data.GetData("Text");
                    if (!String.IsNullOrEmpty(Item))
                        if (Item.EndsWith(".Config", StringComparison.OrdinalIgnoreCase) && !Item.EndsWith(".Config.Config", StringComparison.OrdinalIgnoreCase))
                            if (File.Exists(Item))
                            {
                                Load(Item);
                                return;
                            }
                }
                catch (Exception)
                {

                }
            }
        }

        private void PolicyDrop(String item)
        {

            if (Datas.FileConfiguration != null && item == Datas.FileConfiguration.FullName)
            {

                if (MessageBox.Show("Do you want reload the configuration.", "Configuration file changed", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
                    UCConfigEdit.ConfigEdit.Load(item);

            }
            else
            {
                Load(item);
            }

        }


        private void TreeRoot_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
        {
            //Datas.SaveConfiguration();
        }

        #endregion

        #region others

        public void ShowInherits(Visibility etat)
        {
            if (TreeRoot.Items.Count > 0)
                ShowHide((ElementSection)TreeRoot.Items[0], etat);
        }

        private void ShowHide(ElementSection node, System.Windows.Visibility visibility)
        {
            foreach (ElementSection s in node.Items)
            {
                s.Visibility = System.Windows.Visibility.Visible;

                if (s.ConfigurationElement != null && s.ConfigurationElement is ConfigurationSection)
                {
                    if (!s.ConfigurationElement.ElementInformation.IsPresent)
                        s.Visibility = visibility;
                }
                if (s.HasGroup)
                {
                    ShowHide(s, visibility);
                    bool test = false;
                    foreach (ElementSection s1 in s.Items)
                    {
                        if (s1.Visibility == System.Windows.Visibility.Visible)
                        {
                            test = true;
                            break;
                        }
                    }
                    if (!test)
                        s.Visibility = visibility;
                }
            }

        }

        void h_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
        {
            try
            {
                Process.Start(e.Uri.AbsoluteUri);
            }
            catch (Exception) { }
        }
      
        #endregion


        #endregion  
  
        #region Event Can

        private bool _SectionCanRemove;
        public bool _ItemCanRemove;
        public bool _ItemCanAdd;
        public bool _ItemCanEdit;
        public bool _CanUndo;
        public bool _CanRedo;

        public bool SectionCanRemove
        {
            get { return _SectionCanRemove; }
            set
            {
                if (_SectionCanRemove == value)
                    return;
                _SectionCanRemove = value;
                PropertyChange("SectionCanRemove");
            }
        }

        public bool ItemCanRemove
        {
            get { return _ItemCanRemove; }
            set
            {
                if (_ItemCanRemove == value)
                    return;
                _ItemCanRemove = value;
                PropertyChange("ItemCanRemove");
            }
        }

        public bool ItemCanEdit
        {
            get { return _ItemCanEdit; }
            set
            {
                if (_ItemCanEdit == value)
                    return;
                _ItemCanEdit = value;
                PropertyChange("ItemCanEdit");
            }
        }

        public bool ItemCanAdd
        {
            get { return _ItemCanAdd; }
            set
            {
                if (_ItemCanAdd == value)
                    return;
                _ItemCanAdd = value;
                PropertyChange("ItemCanAdd");
            }
        }

        public bool ItemCanMerge
        {
            get
            {

                return _selectedItem != null &&
                    _selectedItem.ConfigurationElement is ConfigurationSection
                    && !string.IsNullOrEmpty((_selectedItem.ConfigurationElement as ConfigurationSection)
                        .SectionInformation.ConfigSource
                       );
            }
        }

        public bool ItemCanCheck
        {
            get
            {
                return Datas.FileConfiguration != null ; //&& !String.IsNullOrEmpty(Datas.FileConfiguration.FullName);
            }
        }

        public bool CanClearOutput
        {
            get
            {
                return true;
            }
        }

        #region Undo/Redo

        void ListeChange_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            CanUndo = Datas.ListeChange.CanUndo;
            CanRedo = Datas.ListeChange.CanRedo;
        }

        public bool CanUndo
        {
            get { return _CanUndo; }
            set
            {
                if (_CanUndo == value)
                    return;
                _CanUndo = value;
                PropertyChange("CanUndo");
            }
        }

        public bool CanRedo
        {
            get { return _CanRedo; }
            set
            {
                if (_CanRedo == value)
                    return;
                _CanRedo = value;
                PropertyChange("CanRedo");
            }
        }

        public void Undo()
        {
            Datas.ListeChange.Undo();
        }

        public void Redo()
        {
            Datas.ListeChange.Redo();
        }

        #endregion

        #endregion

        #region Select Item

        private void TreeRoot_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {

            LabelDescription.Inlines.Clear();

            SectionCanRemove = false;
            ItemCanRemove = false;
            ItemCanEdit = false;
            ClipboardCanCut = false;

            if (e.NewValue == null)
                return;

            var i = (e.NewValue as ElementSection);

            BuildProperties((ElementSection)e.NewValue);

            if (i.ConfigurationElement == null)
                return;

            i.Children = myproperties.LoadConfig(null);

            if (i.ConfigurationElement != null)
            {
                // si ca plante la c'est qu'il manque une dll.
                try
                {
                    i.Children = myproperties.LoadConfig(i);
                    _selectedItem = i;
                    ShowButton(i);

                }
                catch (Exception ex)
                {
                    SectionCanRemove = false;
                    ItemCanRemove = false;
                    ItemCanEdit = false;
                    MessageBox.Show(ex.Message + @"\n" + ex.StackTrace);
                }
            }

            PropertyChange("ItemCanMerge");
        }

        private void ShowButton(ElementSection i)
        {
            ItemCanAdd = false;

            if (i.CanDel)
            {
                if (i.ConfigurationElement is ConfigurationSection)
                {
                    SectionCanRemove = true;
                    ClipboardCanCut = true;
                }
                else
                {

                    foreach (IElementAction item in i.ButtonActions)
                    {
                        if (!item.IsForChildren)
                        {
                            if (item.TypeAction == EnumAction.Remove)
                                ItemCanRemove = true;
                            else
                                if (item.TypeAction == EnumAction.Edit)
                                    ItemCanEdit = true;
                        }
                    }

                    foreach (IElementAction item in i.ParentItem.ButtonActions)
                    {
                        if (item.IsForChildren)
                            if (item.TypeAction == EnumAction.Remove)
                                ItemCanRemove = true;
                    }


                }
            }

            foreach (IElementAction item in i.ButtonActions)
            {

                if (!item.IsForChildren)
                    if (item.TypeAction == EnumAction.Add)
                        ItemCanAdd = true;

            }

        }

        private void BuildProperties(ElementSection section)
        {

            ConfigurationElement i = section.ConfigurationElement;
            if (i != null)
            {

                if (i is ConfigurationSection)
                    MySectionProeperties.SelectedObject = new PropertiesSection((i as ConfigurationSection));

                else
                    MySectionProeperties.SelectedObject = new PropertiesElement(i.ElementInformation);

            }
            else if (section.HasGroup)
            {
                MySectionProeperties.SelectedObject = section.Group;

            }


        }

        #endregion

        private void SelectionChangedEventHandler(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Count > 0 && e.AddedItems[0] is ConfigProperty)
            {
                ConfigProperty a = (ConfigProperty)e.AddedItems[0];

                LabelDescription.Inlines.Clear();

                if (!string.IsNullOrEmpty(a.Description))
                {

                    Bold b = new Bold();
                    b.Inlines.Add("description : ");
                    LabelDescription.Inlines.Add(b);
                    LabelDescription.Inlines.Add(a.Description);
                    LabelDescription.Inlines.Add(new LineBreak());


                    foreach (BoxSetting item in a.Helpers)
                    {
                        var h = new Hyperlink(new Run(item.Display ?? item.ValueString))
                            {
                                NavigateUri = new Uri(item.ValueString),
                                ToolTip = item.ValueString
                            };

                        h.RequestNavigate += h_RequestNavigate;

                        LabelDescription.Inlines.Add(h);
                        LabelDescription.Inlines.Add(new LineBreak());

                    }
                }

            }
        }

        public event EventHandler<OutputBaseEventHandlerEventArgs> TextInStream;

        protected void PropertyChange(string propertyName)
        {
            if (PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private static LstBox _myproperties;
        public static IEnumerable<ConfigProperty> PropertiesListe
        {
            get
            {
                foreach (ConfigProperty prop in (IEnumerable)_myproperties.DataContext)
                    yield return prop;
            }
        }


        private static IElementSection _selectedItem;
        public static IElementSection SelectedItem
        {
            get
            {
                return _selectedItem;
            }
        }


        public devtm.CommonInteractive.Output Writer { get; set; }


        private static UCConfigEdit _configEdit;
        public static UCConfigEdit ConfigEdit
        {
            get
            {
                return _configEdit;
            }
        }

        internal System.IO.StringReader Output { get; set; }

        public static ElementSection Items { get; private set; }

        /// <summary>
        /// Retourne les proprietes du fichier edité
        /// </summary>
        public ConfigurationsPropertiesSettings ListeProperties
        {
            get
            {
                if (Datas.FileConfiguration != null && !String.IsNullOrEmpty(Datas.FileConfiguration.FullName))
                    return Datas.ConfigurationsProperties[Datas.FileConfiguration.FullName];

                return new ConfigurationsPropertiesSettings();

            }
        }


        public void MergeCurrentSection()
        {

            var section = _selectedItem.ConfigurationElement as ConfigurationSection;
            section.SectionInformation.ConfigSource = string.Empty;

            var p = new PropertiesSection(section);

            MySectionProeperties.SelectedObject = p;

            p.ForceSave = true;

        }


        public void CheckCurrentSection()
        {

            foreach (DirectoryInfo dir in Datas.DirectoriesSearch)
                Datas.ListeAssemblies.AddDirectorySearch(dir);

            string root = Path.GetDirectoryName(Datas.FileConfiguration.FullName);


            foreach (var item in Datas.ListeAssemblies)
            {
                if (item.Loaded 
                    || !(item is AssemblyFileNamespace) 
                    || !item.Filename.StartsWith(root))
                    continue;

           
                item.Initialize();
                item.LoadTypes();

            }


            //Datas.LoadTypes(Datas.DirectoriesSearch);


            IEnumerable<Assembly> asss = Datas.ListeAssemblies.Assemblies.ToList();

            
            int err = 0;

            foreach (ItemSelector item in _listeValidators.Where(c => c.IsChecked))
            {

                Writer.EmptyLine();
                Writer.EmptyLine();
                Writer.WriteLine("---------- Start " + item.Header);

                CommonInteractive.Config.CheckConfig check = null;
                
                try
                {

                    check = Activator.CreateInstance(item.Tag as Type) as CommonInteractive.Config.CheckConfig;
                    check.Events += check_Events;

                    check.ScriptDescriptor = null;
                    check.Log = Writer;
                    check.Assemblies = asss;

                    check.Check(Datas.FileConfiguration.FullName);

                }
                catch (Exception ex)
                {
                    Writer.WriteLine(ex.Message);
                }
                finally
                {
                    if (check != null)
                        check.Events += check_Events;
                }

                Writer.EmptyLine();

                string message = check.Errors.ToString() + " error";
                if (check.Errors > 0)
                    message += "s";

                Writer.WriteLine(message);

                err = err + check.Errors;
                
            }

            Writer.WriteLine("-------------------------------------------");
            Writer.EmptyLine();

            string message2 = "Completed check with " + err.ToString() + " error";
            if (err > 0)
                message2 += "s";

            Writer.WriteLine(message2);

        }

        void check_Events(object sender, CommonInteractive.Config.CheckConfigEventArgs e)
        {

            switch (e.Status)
            {
                case devtm.CommonInteractive.Config.Status.Exception:
                    break;
                case devtm.CommonInteractive.Config.Status.Fail:
                    break;
                case devtm.CommonInteractive.Config.Status.InProgress:

                    if (e.Guid == "69CFB6F2-1D0D-4873-A9A1-22B06035EBC5")
                    {
                        if (e.Path == "SearchType")
                        {

                            BuildTypeExpression pp = e.Data as BuildTypeExpression;
                            string name = pp.AssemblyName;

                            foreach (var item in Datas.ListeAssemblies)
                            {

                                if (item is AssemblyFileNamespace)
                                    if (item.SingleName == name)
                                        return;

                                if (item.Loaded)
                                    continue;

                                if (item.SingleName == name)
                                {
                                    item.Initialize();
                                    item.LoadTypes();

                                    ((e.CheckObject as devtm.CommonInteractive.Config.Config).Assemblies as List<Assembly>).Add(item.Assembly);


                                    return;
                                }
                            }

                            Type t = Type.GetType(pp.AssemblyQualifiedName);
                            if (t != null)
                            {
                                Assembly ass = t.Assembly;
                                Datas.ListeAssemblies.AddGacAssembly(ass);

                                ((e.CheckObject as devtm.CommonInteractive.Config.Config).Assemblies as List<Assembly>).Add(ass);

                            }
                        }
                    }




                    break;
                case devtm.CommonInteractive.Config.Status.Other:
                    break;

                case devtm.CommonInteractive.Config.Status.Successfull:
                case devtm.CommonInteractive.Config.Status.Undefine:
                default:
                    break;
            }

            



        }

        #region SaveParemeters


        public UCConfigEdit.SaveParameters SaveParameter { get; set; }

        public class SaveParameters
        {

            public SaveParameters()
            {
                Fusion = true;
            }
            public bool Fusion { get; set; }
            public ConfigurationSaveMode ConfigurationMode { get; set; }
            public bool ForceSave { get; set; }

        }

        public RecentFiles RecentFiles { get { return Datas.RecentFiles; } }

        #endregion

        #region Clipboard

        private bool _clipboardCanCut;
        public bool ClipboardCanCut
        {
            get { return _clipboardCanCut; }
            set
            {
                if (_clipboardCanCut == value)
                    return;

                _clipboardCanCut = value;

                PropertyChange("ClipboardCanCut");
            }
        }        

 
        public void ClipboardCut()
        {
            if (_selectedItem == null)
                return;

            var s = _selectedItem.CastToClipboard();
            Clipboard.SetData(ClipboardFormat, s);

        }

        public void ClipboardCopy()
        {
            if (_selectedItem == null)
                return;

            var s = _selectedItem.CastToClipboard();            
            Clipboard.SetData(ClipboardFormat, s);

        }

        public void ClipboardPaste()
        {

            string s = (string)Clipboard.GetData(ClipboardFormat);
            string[] tb = s.Split(ElementSection.spliter);

            string name = tb[0];
            string type = tb[1];
            string ProtectionProvider = tb[2];
            string ConfigSource = tb[3];
            string value = tb[4];

            // resolver

            Type t;
            using (ResolveWorker i = new ResolveWorker(Datas.Lazy.Resolver))
            {
                t = Type.GetType(type);
            }

            if (t != null)
            {
                ConfigurationSection section = (ConfigurationSection)Activator.CreateInstance(t, null);
                section.SectionInformation.SetRawXml(value);
                CreateSection(section, name);
            }
        }

        public const string ClipboardFormat = "SectionClipboardFormat";

        #endregion

        #region Validators
        
        private ObservableCollection<ItemSelector> _listeValidators = new ObservableCollection<ItemSelector>();
        public ObservableCollection<ItemSelector> ListeValidators
        {
            get
            {

                if (_listeValidators.Count() == 0)
                {
                    Datas.ListeAssemblies.Types.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Types_CollectionChanged);

                    Datas.ListeAssemblies.AddFileAssembly(typeof(devtm.CommonInteractive.Config.CheckConfig).Assembly);

                    Datas.ListeAssemblies.Initialize();
                    Datas.ListeAssemblies.LoadTypes();
                }
                return _listeValidators;
            }
        }

        void Types_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {

            e.ApplyChange<DescType>
                (
                    item => AddItemSelector(item.Type)
                );

        }

        private void AddItemSelector(Type type)
        {

            if (!type.IsOfType(typeof(devtm.CommonInteractive.Config.CheckConfig)))
                return;

            if (type.FullName == "devtm.CommonInteractive.Config.CheckConfig")
                return;

            string displayName = type.Name;
            string description = type.Name;
            string guidString = string.Empty;

            DisplayNameAttribute[] displays = (DisplayNameAttribute[])type.GetCustomAttributes(typeof(DisplayNameAttribute), false);
            foreach (DisplayNameAttribute item in displays)
                displayName = item.DisplayName;

            DescriptionAttribute[] descriptions = (DescriptionAttribute[])type.GetCustomAttributes(typeof(DescriptionAttribute), false);
            foreach (DescriptionAttribute item in descriptions)
                description = item.Description;

            GuidAttribute[] guids = (GuidAttribute[])type.GetCustomAttributes(typeof(GuidAttribute), false);
            foreach (GuidAttribute item in guids)
                guidString = item.Value;

            _listeValidators.Add(new ItemSelector() { Tag = type, IsChecked = true, Header = displayName, Description = description, Guid = guidString });

        }

        #endregion

    }

}


